
local require = require
local setmetatable = setmetatable
local error = error
local table = table
local ngx = ngx
local os = os
local string = string
local tonumber = tonumber
local math = math
local pairs = pairs
local io = io
local type = type
local util = require "util"
local conf = require "conf"
local protocal = require "protocal"
local message = require 'message'
package.cpath = "/opt/xyitech/jieyan-backend-production/xbit/?.so"
local xbit = require("xbit")
package.cpath = "/usr/nginx/?.so;;"
local json = require 'cjson'

module(...)

local _fids = util.getChannel("fids")
_VERSION = '0.1'
 _int32_t = 0
 _int16_t = 1
 _float = 2
 _uint32_t = 4
 _uint16_t = 5
 _uint8_t = 6
 _int8_t = 7
 _jieyan_takeoff_admin = 107
_STATES_TRANS = {
    [0] = {1, 8, 10},
    [1] = {10},
    [2] = {3, 4, 5, 9},
    [3] = {2, 4},
    [4] = {},
    [5] = {4},
    [6] = {8,1,7,2,10},
    [7] = {8,1,6,2,10},
    [8] = {1, 6, 7},
    [9] = {2, 8},
    [10] = {0, 1},
    -- [11] = {0, 10}
}

function create(user, args)
    local spoint = require 'spoint'
    local routeId, remark, weight, fid, flight_number, schedule_id = args.routeid, args.remark, args.weight, args.fid, args.flight_number, args.schedule_id
    local paper, letter, magzine, package, other = args.paper, args.letter, args.magzine, args.package, args.other, args.state
    local route, height_diff, to_uid, to_uid2
    local red = conf.get_redis()
    local db = conf.get_mysql()
    local vals = {}
    local maxWeight = 0
    if routeId then
        vals[#vals + 1] = "route = " .. routeId
    end
    if fid then
        vals[#vals + 1] = "fid = " .. ngx.quote_sql_str(fid)
        local res = db:query("SELECT id, serial_no from `order` where fid = " .. fid .. " AND state = 2")
        if res and #res >= 1 then
            ngx.print(json.encode({
                err = 6,
                msg = '该飞机存在超过1个未正常着陆且未确认的订单，' .. json.encode(res)
            }))
            ngx.exit(200)
        end
    end
    
    vals[#vals + 1] = "aid = " .. user.aid
    vals[#vals + 1] = "org_id = " .. user.org_id
    vals[#vals + 1] = "uid = " .. user.id
    if weight then
        vals[#vals + 1] = "weight = " .. weight
    end
    if remark then
        vals[#vals + 1] = "remark = " .. ngx.quote_sql_str(remark)
    end
    vals[#vals + 1] = "t0 = " .. os.time()
    vals[#vals + 1] = "state = 0"
    
    local res = db:query("SELECT `spoint`.uid, `spoint`.uid2, `route`.detail, `route`.sid, `route`.eid from `route` left join `spoint` on `route`.eid = `spoint`.id where `route`.id = " .. routeId)
        if res and res[1] and res[1].detail then
            route = json.decode(res[1].detail)
            height_diff = spoint.getHeightDiffBySpointIds(res[1].sid, res[1].eid)
            to_uid = res[1].uid
            to_uid2 = res[1].uid2
        else
            ngx.print(json.encode({
                err = 2,
                msg = '航路不存在'
            }))
            ngx.exit(200)
        end
    if not flight_number then
        local schedule = require "schedule"
        flight_number = schedule.getTempId(user.id, res[1].sid, res[1].eid)
    end
    local serial_no = _getSerialNo(os.time(), flight_number)
    vals[#vals + 1] = "serial_no = " .. ngx.quote_sql_str(serial_no)
    local content = {["paper"] = 0, ["magzine"] = 0, ["letter"] = 0, ["package"] = 0, ["other"] = 0}

    local res, err = red:get(_fids)
    if err then
        ngx.print(json.encode({
            err = 12,
            msg = 'redis错误'
        }))
    end

    -- if uid ~= 95 and fid then
    --     if res == ngx.null  or not util.contains(json.decode(res), fid.."") then
    --         ngx.print(json.encode({
    --             err = 10,
    --             msg = '飞机未在线'
    --         }))
    --         ngx.exit(200)
    --     end

    --     local volt = red:get('voltage_' .. fid)
    --     local res, err  = db:query("SELECT model, weight from `plane` where id = " .. fid)
    --     if not res or #res == 0 then
    --         ngx.print(json.encode({
    --             err = 10,
    --             msg = '飞机信息有误'
    --         }))
    --         ngx.exit(200)
    --     end
    --     local model = res[1].model
    --     local planeWeight = res[1].weight
    --     if volt == ngx.null then
    --         volt = 0
    --     end
    --     -- volt = volt == ngx.null or volt and 0
    --     local flightTime = util.flightTime(route, height_diff)
    --     local maxWeight = util.maxWeight(volt, tonumber(planeWeight), flightTime)
    --     -- if tonumber(weight) * 1000 > maxWeight
    --     ngx.log(ngx.ERR, maxWeight)

    --     local plane = require "plane"
    --     local enoughBattery, batteryAfterFlight = plane.checkPlaneBatteryStatus(route, height_diff, tonumber(volt), planeWeight, weight, model)
    --     if model ~= "SIM" and enoughBattery then
    --         ngx.print(json.encode({
    --             err = 5,
    --             msg = '抱歉，电池余量不足，请更换电池或选择其他较短航线'
    --         }))
    --         ngx.exit(200)
    --     end
    -- end
    if height_diff then
        vals[#vals + 1] = "height_diff = " .. height_diff
    end    

    if paper then 
        content["paper"] = tonumber(paper)
    end
    if magzine then 
        content["magzine"] = tonumber(magzine)
    end
    if letter then 
        content["letter"] = tonumber(letter)
    end
    if package then 
        content["package"] = tonumber(package)
    end
    if other then
        content["other"] = tonumber(other)
    end
    vals[#vals + 1] = "content = '" .. json.encode(content) .."'"

    vals[#vals + 1] = "to_uid = " .. to_uid
    vals[#vals + 1] = "to_uid2 = " .. to_uid2


    vals[#vals + 1] = "sender = '" .. user.name .. "'"
    vals[#vals + 1] = "senderPhone = '" .. user.phone .. "'"
    if flight_number then
        vals[#vals + 1] = "flight_number = '" .. flight_number .. "'"
    end

    if schedule_id then
        vals[#vals + 1] = "schedule_id = " .. schedule_id
    end
    local res = db:query("INSERT INTO `order` SET " .. table.concat(vals, ","))
    return res
end

function createController(user, args)
    local res = create(user, args)
    local db = conf.get_mysql()

    if not res or res.affected_rows < 1 then
        ngx.print(json.encode({
            err = 1,
            msg = '创建失败'
        }))
        ngx.exit(200)
    else
        local insert_id = res.insert_id
        if insert_id < 1 then
            res = db:query("SELECT LAST_INSERT_ID() AS insert_id")
            if res and res[1] and res[1].insert_id then
                insert_id = res[1].insert_id
            end
        end
        ngx.print(json.encode({
            err = 0,
            id = insert_id,
            msg = '创建成功',
            maxWeight = maxWeight
        }))
        ngx.exit(200)
    end
end

function list(user, args)
    local db = conf.get_mysql()
    local sql = "SELECT * FROM `order` WHERE 1=1"
    sql = sql .. " AND aid in (" ..  table.concat(user.aids, ",") .. ")"
    sql = sql .. " AND org_id in (" ..  table.concat(user.orgIds, ",") .. ")"

    if args.page_no and args.page_size then
        sql = sql .. " AND state != 10 ORDER BY id DESC LIMIT " .. (args.page_no * args.page_size) .. "," .. args.page_size
    end
    local res = db:query(sql)

    if not res then
        return nil
    else
        local routes = db:query("SELECT * FROM `route`")
        if not routes then
            return nil
        end
        for key,value in pairs(res) do
            for i = 1, #routes do
                if res[key].route == routes[i]["id"] then
                    res[key].route = routes[i]
                end
            end
        end
        return res
    end
end

function listController(user, args)
    local res = list(user, args)
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '未找到相应的订单'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            orders = res
        }))
        ngx.exit(200)
    end
end

function update(user, args)
    local id, state, info, landing, weight, flight_number, schedule_id, fid = tonumber(args.id), args.state, args.info, args.landing, args.weight, args.flight_number, args.schedule_id, args.fid
    local paper, letter, magzine, package, other = args.paper, args.letter, args.magzine, args.package, args.other
    local err = nil
    local msg = ""
    local db = conf.get_mysql()
    local redis = conf.get_redis()
    local vals = {}
    id = tonumber(id)
    if not id then
        ngx.print(json.encode({
            err = 1,
            msg = '参数不正确'
        }))
        ngx.exit(200)
    end
    local before = db:query("SELECT state, content, fid, aid, bid, serial_no, route, to_uid, to_uid2 from `order` WHERE id = " .. id .. " AND aid in (" ..  table.concat(user.aids, ",") .. ")")
    if not before or not before[1] then
        ngx.print(json.encode({
            err = 3,
            msg = '权限不足'
        }))
        ngx.exit(200)
    end
    local beforeState = before[1]["state"] or nil
    local serial_no = before[1]["serial_no"]
    if state then
        state = tonumber(state)
        ngx.log(ngx.ERR, state)
        ngx.log(ngx.ERR, beforeState)
        if not args.autoApprove and not stateChangeCheck(beforeState, state) then
            ngx.print(json.encode({
                err = 2,
                msg = '该状态不允许转换'
            }))
            ngx.exit(200)
        end
        
        if args.resetTimes then
            vals[#vals + 1] = "t0 = " .. os.time()
            vals[#vals + 1] = "t1 = " .. 0
            vals[#vals + 1] = "t2 = " .. 0
            vals[#vals + 1] = "t3 = " .. 0
            vals[#vals + 1] = "t4 = " .. 0
            vals[#vals + 1] = "t5 = " .. 0
            vals[#vals + 1] = "t6 = " .. 0
            vals[#vals + 1] = "t7 = " .. 0
            vals[#vals + 1] = "t8 = " .. 0
            vals[#vals + 1] = "t9 = " .. 0
            vals[#vals + 1] = "t10 = " .. 0
            vals[#vals + 1] = "jieyan_admin_status = " .. 0
            vals[#vals + 1] = "spoint_admin_status = " .. 0
        end

        if args.autoApprove then
            vals[#vals + 1] = "t6 = " .. os.time()
            vals[#vals + 1] = "t7 = " .. os.time()
            vals[#vals + 1] = "t8 = " .. os.time()

            vals[#vals + 1] = "jieyan_admin_status = " .. 1
            vals[#vals + 1] = "spoint_admin_status = " .. 1
        end

        local stateChangeTime = os.time()
        vals[#vals + 1] = "state = " .. state
        vals[#vals + 1] = "t" .. state .. " = " .. stateChangeTime
        ngx.log(ngx.ERR, json.encode(before))
        if state == 1 and before[1].fid then
            -- local res = db:query("SELECT name from `plane` where id = " .. before[1].fid)
            -- if res then
            --     local res = db:query("UPDATE `plane` SET status = 0 where id = " .. before[1].fid)
            -- else
            --     ngx.print(json.encode({
            --         err = 2,
            --         msg = '飞机信息有误'
            --     }))
            --     ngx.exit(200)
            -- end
        elseif state == 2 and before[1].fid then
            local res = db:query("SELECT name from `plane` where id = " .. before[1].fid)
            if res then
                ngx.log(ngx.ERR, json.encode(res))
                
            else
                ngx.print(json.encode({
                    err = 2,
                    msg = '飞机信息有误'
                }))
                ngx.exit(200)
            end
        elseif (state == 4 or state == 5) and before[1].fid then
            local eid = nil
            local duration = 0
            if args.fromApp then
                if tonumber(before[1].to_uid) ~= tonumber(user.id) and tonumber(before[1].to_uid2) ~= tonumber(user.id) then
                    ngx.print(json.encode({
                        err = 2,
                        msg = '收件人不符'
                    }))
                    ngx.exit(200)
                end

                vals[#vals + 1] = "receiver = '" .. user.name .. "'"
                vals[#vals + 1] = "receiverPhone = '" .. user.phone .. "'"
                if before[1] and before[1].route then

                    local res = db:query("SELECT sid, eid, duration, (select name from `spoint` where id = `route`.sid) as sname, (select name from `spoint` where id = `route`.eid) as ename FROM `route` where id = " .. before[1].route)
                    if res and res[1] and res[1].eid then
                        eid = res[1].eid
                        if state == 5 then
                            duration = os.time() - tonumber(before[1].t2)
                        else
                            duration = res[1].duration
                        end
                    end
                    message.createOrderConfirmMessage(user, {["sname"] = res[1].sname, ["ename"] = res[1].ename, ["serial_no"] = serial_no})
                    local body = user.name .. "于" .. os.date("%H:%M", os.time()) .. "收到了从" .. res[1].sname .. "-" .. res[1].ename .. "的快递"
                    message.create(user, {["to_uid"] = 0, ["type"] = "normal", ["header"] = "系统消息", ["body"] = body})
                end
                
            end


            redis:del("order_"..before[1].fid)
            redis:del("batteryAfterFlight_"..before[1].fid)
            redis:del("actualWeight_".. before[1].fid)
            local planeVals = {}
            planeVals[#planeVals + 1] = "status = 0"
            planeVals[#planeVals + 1] = "last_flight_time = " .. os.time()
            if eid and tonumber(eid) then
                planeVals[#planeVals + 1] = "spoint_id = " .. tonumber(eid)
            end
            local battery = require 'battery'
            if before[1].bid  and before[1].bid ~= 0 then
                local res = battery.search(user, {["id"] = before[1].bid})
                local batteryArgs = {}
                -- if res and res[1] and res[1].charged == 1 then
                    -- battery.id = bid
                    -- batteryArgs.use_count = 1
                    -- batteryArgs.charged = 0
                -- end
                
                batteryArgs.id = before[1].bid
                batteryArgs.inc = true
                batteryArgs.use_time = duration
                batteryArgs.spoint_id = eid
                batteryArgs.serial_no = serial_no
                batteryArgs.last_use_time = os.time()
                battery.update(user, batteryArgs)
            end
            local res = db:query("UPDATE `plane` SET " .. table.concat(planeVals, ",") .. " WHERE id = " .. before[1]["fid"])
        end
    end
    local content = {}
    if before and before[1] and before[1].content then
        content = json.decode(before[1].content)
    end

    if paper then 
        content["paper"] = tonumber(paper)
    end
    if magzine then 
        content["magzine"] = tonumber(magzine)
    end
    if letter then 
        content["letter"] = tonumber(letter)
    end
    if package then 
        content["package"] = tonumber(package)
    end
    if other then
        content["other"] = tonumber(other)
    end
    vals[#vals + 1] = "content = '" .. json.encode(content) .."'"

    if info then
        vals[#vals + 1] = "info = '" .. info .."'"
    end

    if args.plane_version_number then
        vals[#vals + 1] = "plane_version_number = " .. ngx.quote_sql_str(args.plane_version_number)
    end

    if args.plane_hashcode then
        vals[#vals + 1] = "plane_hashcode = " .. ngx.quote_sql_str(args.plane_hashcode)
    end

    if landing then
        vals[#vals + 1] = "landing = '" .. landing .."'"
    end
    if weight then
        vals[#vals + 1] = "weight = '" .. weight .."'"
    end

    if args.remark then
        vals[#vals + 1] = "remark = '" .. args.remark .."'"
    end

    if args.bid then
        vals[#vals + 1] = "bid = " .. args.bid
    end

    if flight_number then
        vals[#vals + 1] = "flight_number = '" .. flight_number .. "'"
    end
    if args.jieyan_admin_status then
        vals[#vals + 1] = "jieyan_admin_status = " .. args.jieyan_admin_status
    end
    if args.spoint_admin_status then
        vals[#vals + 1] = "spoint_admin_status = " .. args.spoint_admin_status
    end
    if args.jieyan_admin_uid then
        vals[#vals + 1] = "jieyan_admin_uid = " .. args.jieyan_admin_uid
    end
    if args.spoint_admin_uid then
        vals[#vals + 1] = "spoint_admin_uid = " .. args.spoint_admin_uid
    end

    if schedule_id then
        vals[#vals + 1] = "schedule_id = " .. schedule_id
    end

    if args.actual_distance then
        vals[#vals + 1] = "actual_distance = " .. args.actual_distance
    end

    local res = db:query("UPDATE `order` SET " .. table.concat(vals, ",") .. " WHERE id = " .. id) --.. " AND aid = " .. aid)
    if not res or res.affected_rows < 1 then
        err = 99
        msg = '更新失败'
    else
        err = 0
        msg = '更新成功'
    end
    return {err = err, msg = msg }
end

function updateController(user, args)
    local res = update(user, args)
    ngx.log(ngx.ERR, json.encode(args))
    ngx.log(ngx.ERR, err, msg)
    ngx.print(json.encode({
        err = res.err,
        state = args.state,
        osTime = os.time(),
        msg = res.msg
    }))
    ngx.exit(200)
end

function stateChangeCheck(before, after)
    if not before then
        return true
    elseif not after then
        return false
    elseif before == after then
        return true
    end

    local statesAfter = _STATES_TRANS[before]
    if statesAfter then
        return require("util").contains(statesAfter, after)
    end
    return false
end

function takeOffPreCheck(user, args)
    local id, state, fid, bid, charged = tonumber(args.id), tonumber(args.state), tonumber(args.fid), tonumber(args.bid), args.charged
    local plane = require "plane"
    local red = conf.get_redis()
    local err = 0
    local msg = "起飞成功"
    local vals = {}
    local db = conf.get_mysql()
    local stateChangeTime = os.time()
    local enoughBattery, batteryAfterFlight
    local route, height_diff, packageWeight, planeWeight, model, planeMaxWeight

    if not id then
        ngx.print(json.encode({
            err = 1,
            msg = '参数不正确'
        }))
        ngx.exit(200)
    end
    if tonumber(user.id) == 95 then
        return "ok", 0, 0.2
    else
        local now = os.time()
        local res = db:query("SELECT uid, fid, height_diff, route, serial_no, weight,t6, t7,jieyan_admin_status,spoint_admin_status, state from `order` where id = " .. id)
        if res and res[1] then
            ngx.log(ngx.ERR, res[1].fid)
            ngx.log(ngx.ERR, fid)
            if res[1].uid ~= user.id then
                ngx.print(json.encode({
                    err = 2,
                    msg = '发件人不符合'
                }))
                ngx.exit(200)
            end
       
            if not stateChangeCheck(tonumber(res[1].state), tonumber(args.state)) then
                ngx.print(json.encode({
                    err = 2,
                    msg = '该状态不允许起飞'
                }))
                ngx.exit(200)
            end

            if res[1].jieyan_admin_status ~= 1 or res[1].spoint_admin_status ~= 1 then
                ngx.print(json.encode({
                    err = 1,
                    msg = '审核不通过无法起飞'
                }))
                ngx.exit(200)
            end
            
            if res[1].t6 == 0 then
                ngx.print(json.encode({
                    err = 1,
                    msg = '后台尚未审核'
                }))
                ngx.exit(200)
            elseif (now - res[1].t6 > 600) then
                ngx.print(json.encode({
                    err = 1,
                    msg = '后台审核已过期'
                }))
                ngx.exit(200)
            end

            if res[1].t7 == 0 then
                ngx.print(json.encode({
                    err = 1,
                    msg = '收件站点尚未审核'
                }))
                ngx.exit(200)
            elseif (now - res[1].t7 > 600) then
                ngx.print(json.encode({
                    err = 1,
                    msg = '收件站点审核已过期'
                }))
                ngx.exit(200)
            end

            if not tonumber(res[1].fid) and fid then
                db:query("UPDATE `order` SET fid = " .. fid .. " WHERE id = " .. id)
            elseif tonumber(res[1].fid) then
                fid = tonumber(res[1].fid)
            else
                ngx.print(json.encode({
                    err = 2,
                    msg = '订单信息有误'
                }))
                ngx.exit(200)
            end
            
            route = res[1].route
            args.serial_no = res[1].serial_no
            height_diff = res[1].height_diff
            packageWeight = tonumber(res[1].weight)
        else
            ngx.print(json.encode({
                err = 2,
                msg = '订单信息有误'
            }))
            ngx.exit(200)
        end
        -- ngx.log(ngx.ERR, route)
        local res = db:query("SELECT `spoint`.uid, `spoint`.uid2, `route`.detail from `route` left join `spoint` on `route`.eid = `spoint`.id where `route`.id = " .. route)
        if res and res[1] and res[1].detail then
            route = json.decode(res[1].detail)
            if res[1].uid == 0 and res[1].uid2 == 0 then
                ngx.print(json.encode({
                    err = 2,
                    msg = '该站点尚未指定收件人'
                }))
            ngx.exit(200)
            end
        else
            ngx.print(json.encode({
                err = 2,
                msg = '航路不存在'
            }))
            ngx.exit(200)
        end
        local res = db:query("SELECT id from `order` where fid = " .. fid .. " AND state = 2")
        if res and #res >= 1 then
            ngx.print(json.encode({
                err = 6,
                msg = '该飞机存在超过1个未正常着陆且未确认的订单，请查看并确认之前订单'
            }))
            ngx.exit(200)
        end

        local res = db:query("SELECT name, aid, status, weight,max_weight, model from `plane` where id = " .. fid)
        if res and res[1] then
            -- local serial_no = _getSerialNo(os.time(), res[1]["name"])
            -- vals[#vals + 1] = "serial_no = '" .. serial_no .. "'"
            planeWeight = tonumber(res[1].weight)
            planeMaxWeight = tonumber(res[1].max_weight)

            model = res[1].model
            if not util.contains(user.aids, res[1]["aid"]) then
                ngx.print(json.encode({
                    err = 4,
                    msg = '该飞机不在区域内'
                }))
                ngx.exit(200)
            end

            if res[1]["status"] ~= 0 then
                ngx.print(json.encode({
                    err = 5,
                    msg = '飞机该状态不允许起飞，请去云平台检查飞机状态'
                }))
                ngx.exit(200)
            end 
        else
            ngx.print(json.encode({
                err = 3,
                msg = '飞机信息有误'
            }))
            ngx.exit(200)
        end
        local res
        res, err = red:get(_fids)
        if err then
            ngx.print(json.encode({
                err = 12,
                msg = 'redis错误'
            }))
        end

        if res == ngx.null  or not util.contains(json.decode(res), fid.."") then
            ngx.print(json.encode({
                err = 10,
                msg = '飞机未在线'
            }))
            ngx.exit(200)
        end
        if planeMaxWeight and planeMaxWeight ~= 0 then
            local n = planeMaxWeight - planeWeight - packageWeight 
            if n < 0 then
                ngx.print(json.encode({
                    err = 6,
                    msg = '抱歉，您的货物重量超过了最大安全重量，请减少' .. string.format("%0.1f", math.abs(n)) .. 'kg货物后再试'
                }))
                ngx.exit(200)
            end
        end

        local volt
        volt, err = red:get('voltage_' .. fid)
        enoughBattery, batteryAfterFlight = plane.checkPlaneBatteryStatus(route, height_diff, tonumber(volt), planeWeight, packageWeight, model)
        if model ~= "SIM" and enoughBattery then
            ngx.print(json.encode({
                err = 5,
                msg = '抱歉，电池余量不足，请更换电池或选择其他较短航线'
            }))
            ngx.exit(200)
        end
        if planeWeight and packageWeight then
            local throttle = util.getThrottle(tonumber(planeWeight) + tonumber(packageWeight), tonumber(volt) / 1000)
            args.throttle = throttle
        end
    end
    local res, err = red:set('batteryAfterFlight_' .. fid, batteryAfterFlight)
    return msg, 0, batteryAfterFlight
end

function takeOffPreCheckController(user, args)
    local msg, err,  batteryAfterFlight = takeOffPreCheck(user, args)
    ngx.log(ngx.ERR, msg)
    ngx.log(ngx.ERR, err)
    ngx.log(ngx.ERR, batteryAfterFlight)

    ngx.print(json.encode({
        err = err,
        msg = msg,
        batteryAfterFlight = string.format("%0.1f", batteryAfterFlight * 100)..'%'
    }))
end

function _autoTakeOff(user, args)
    local id, state, fid, bid, charged = tonumber(args.id), tonumber(args.state), tonumber(args.fid), tonumber(args.bid), args.charged
    local plane = require "plane"
    local battery = require "battery"
    local red = conf.get_redis()
    local err = 1
    local msg = "起飞失败"
    local vals = {}
    local db = conf.get_mysql()
    local stateChangeTime = os.time()

    if tonumber(user.id) == 95 then
        vals[#vals + 1] = "state = " .. state
        vals[#vals + 1] = "t" .. state .. " = " .. os.time()


        local sql = "UPDATE `order` SET " .. table.concat(vals, ",") .. " WHERE id = " .. id .. " AND aid = " .. user.aid
        ngx.log(ngx.ERR, sql)

        local res = db:query(sql)
        ngx.print(json.encode({
            err = 0,
            state = state,
            osTime = os.time(),
            msg = "起飞成功"
        }))
        ngx.exit(200)
    end
        local msg, err, batteryAfterFlight = takeOffPreCheck(user, args)
        if state == 2 then
            local plane = require("plane")
            local body = plane.autoTakeOff(user, args)
            
            if body and type(body) == "table" then
                ngx.log(ngx.ERR, json.encode(body))
                -- body = json.decode(body)
            else
                ngx.log(ngx.ERR, body)
            end
            if body and body.err then

                err = body.err
                msg = body.msg
                state = 9
                if tonumber(body.err) == 0 then
                    state = 2
                    local res = db:query("UPDATE `plane` SET status = 1 WHERE id = " .. fid)
                    -- if bid and charged then
                    --     battery.update(user, {["id"] = bid, ["charged"] = 1})  
                    -- end
                end
            end
        end

    local actualWeight = red:get("actualWeight_"..fid)
    if actualWeight == ngx.null then
        actualWeight = 0
    end

    vals[#vals + 1] = "actual_weight = " .. actualWeight
    vals[#vals + 1] = "battery_after_flight = " .. batteryAfterFlight
    vals[#vals + 1] = "state = " .. state
    vals[#vals + 1] = "t" .. state .. " = " .. os.time()
    if bid then
        vals[#vals + 1] = 'bid = ' .. bid
    end

    local sql = "UPDATE `order` SET " .. table.concat(vals, ",") .. " WHERE id = " .. id .. " AND aid = " .. user.aid
    local res = db:query(sql)
    if not res or res.affected_rows < 1 then
        err = 99
        msg = '更新失败'
    end

    ngx.log(ngx.ERR, err)
    ngx.log(ngx.ERR, msg)
     ngx.print(json.encode({
        err = err,
        state = state,
        osTime = os.time(),
        msg = msg
    }))
    ngx.exit(200)
end


function detail(user, args)
    local db = conf.get_mysql()
    local sql = "SELECT * FROM `order` WHERE id = " .. args.id .. " AND aid in (" ..  table.concat(user.aids, ",") .. ")"
    ngx.log(ngx.ERR, sql)
    local res = db:query(sql)
    if not res or not res[1] then
        return nil
    end
    res[1].route = require("config").get_route(res[1].route)
    return res
end

function detailController(user, args)
    if not args.id then
        ngx.print(json.encode({
            err = 1,
            msg = '参数不正确'
        }))
        ngx.exit(200)
    end
    local res = detail(user, args)
    if not res or not res[1] then
        ngx.print(json.encode({
            err = 1,
            msg = '未找到相应的订单'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            order = res[1],
            osTime = os.time()
        }))
        ngx.exit(200)
    end
end

function search(user, args)
    local page_no, page_size, name, state, date, serial_no, sname, ename, fid, aid, flight_number, schedule_id = tonumber(args.page_no), tonumber(args.page_size), args.name, args.state, args.date, args.serial_no, args.sname, args.ename, args.fid, args.aid, args.flight_number, args.schedule_id
    local sender, receiver, id_start, id_end, start_date, end_date, uids = args.sender, args.receiver, tonumber(args.id_start), tonumber(args.id_end), args.start_date, args.end_date, args.uids
    local notSim, yearDate = args.notSim, args.yearDate
    local db = conf.get_mysql()
    local now = os.time()

    local sql = "SELECT `order`.id, `order`.bid,`order`.actual_weight,`order`.weight, `order`.battery_after_flight,`order`.plane_hashcode, `order`.plane_version_number, `order`.fid,`order`.aid,`order`.uid,`order`.route AS routeId, `order`.to_uid,`order`.jieyan_admin_status,`order`.spoint_admin_status,`order`.jieyan_admin_uid,`order`.spoint_admin_uid,`order`.to_uid2, `order`.serial_no, `order`.sender, `order`.receiver,`order`.senderPhone, `order`.receiverPhone, (SELECT name from spoint where id = (SELECT sid from route where id = `order`.route)) AS sname, (SELECT name from spoint where id = (SELECT eid from route where id = `order`.route)) AS ename, `order`.t0, `order`.t1, `order`.t2,`order`.t3, `order`.t4, `order`.t5, `order`.t6,`order`.t7,`order`.t8,`order`.t9,`order`.t10,`order`.content, `order`.weight, `order`.info, `order`.landing, `order`.fid, `plane`.model, `plane`.name, (SELECT name FROM spoint WHERE id = plane.spoint_id) AS 'airport', `order`.state,`order`.schedule_id, `order`.flight_number,`route`.distance, `route`.duration,`order`.height_diff,`route`.name as routeName, `order`.actual_distance FROM `order` left join `plane` on `order`.fid = `plane`.id left join `route` on `order`.route = `route`.id WHERE 1 = 1";
     if name then
        sql = sql .. " AND `plane`.name like '%" .. name .. "%'"
    end

    if args.id then
        sql = sql .. " AND `order`.id = " .. args.id
    end
    if id_start and id_end then
        sql = sql .. " AND `order`.id between ".. id_start .. " AND " .. id_end
    end
    if serial_no then
        sql = sql .. " AND `order`.serial_no like '%" .. serial_no .. "%'"
    end
    if uids then
        sql = sql .. " AND `order`.uid in (" .. uids .. ")"
    end
    if args.to_uid then
        sql = sql .. " AND (`order`.to_uid = " .. args.to_uid .. " OR `order`.to_uid2 = " .. args.to_uid .. ")"
    end
    if start_date and end_date then
        sql = sql .. " AND `order`.t0 between unix_timestamp('" .. start_date .. " 00:00:00') and unix_timestamp('" .. end_date .. " 23:59:59')"  
    end
    -- if yearDate then
    --     sql =  sql .. " AND `order`.t0 > " .. tonumber(yearDate)
    -- end

    if args.start_time then
        sql = sql .. " AND `order`.t0 >= " .. args.start_time
    end
    
    if args.end_time then
        sql = sql .. " AND `order`.t0 <= " .. args.end_time
    end


    if notSim then
        sql =  sql .. " AND `plane`.model != 'SIM' "
    end

    if state and tonumber(state) then
        sql = sql .. " AND `order`.state = " .. tonumber(state)
    end
    if date then
        sql = sql .. " AND `order`.t0 between unix_timestamp('" .. date .. " 00:00:00') and unix_timestamp('" .. date .. " 23:59:59')"  
    end
    if sname then
        sql = sql .. " AND `order`.route in (SELECT id FROM `route` where `route`.sid in (SELECT id from `spoint` WHERE `spoint`.name like '%".. sname .. "%'))"
    end
    if ename then
        sql = sql .. " AND `order`.route in (SELECT id FROM `route` where `route`.eid in (SELECT id from `spoint` WHERE `spoint`.name like '%".. ename .. "%'))"
    end

    if aid then
        local ids = conf.get_aids(tonumber(aid))
        ngx.log(ngx.ERR, json.encode(ids))
        sql = sql .. " AND `order`.aid in (" ..  table.concat(ids, ",") .. ")" 
    end

    if args.org_id then
        local ids = conf.get_orgIds(tonumber(args.org_id))
        sql = sql .. " AND `order`.org_id in (" ..  table.concat(ids, ",") .. ")"
    end

    if sender then
        sql = sql .. " AND `order`.sender like '%" .. sender .. "%'"
    end

    if args.uid then
        sql = sql .. " AND (`order`.uid = " .. user.id .. " OR `order`.to_uid = " .. user.id .. " OR `order`.to_uid2 = " .. user.id .. ")"
    end

    if args.to_uid then
        sql = sql .. " AND (`order`.to_uid = " .. args.to_uid .. " OR `order`.to_uid2 = " .. args.to_uid .. ")"
    end

    if fid and tonumber(fid) then
        sql = sql .. " AND `order`.fid = " .. fid
    end

    if schedule_id and tonumber(schedule_id) then
        sql = sql .. " AND `order`.schedule_id = " .. schedule_id
    end

    if scheduleIds then
        sql = sql .. "AND `order`.schedule_id in (" ..  table.concat(scheduleIds, ",") .. ")"
    end

    if flight_number then
        sql = sql .. " AND `order`.flight_number like '%" .. flight_number .. "%'"
    end

    if receiver then
        sql = sql .. " AND `order`.receiver like '%" .. receiver .. "%'"
    end

    sql = sql .. " AND `order`.aid in (" ..  table.concat(user.aids, ",") .. ")"

    sql = sql .. " AND `order`.org_id in (" ..  table.concat(user.orgIds, ",") .. ")"

    sql = sql .. " AND `order`.state != 10 ORDER BY `order`.t0 DESC"

    ngx.log(ngx.ERR, sql)
    local resBeforePageSize = db:query(sql)
    local count = #(resBeforePageSize or {})
    local orderStats = sortOrderStats(resBeforePageSize, start_date, end_date)

    if page_no and page_size then
        sql = sql ..  " LIMIT " .. page_no * page_size .. "," .. page_size
    end

    local res = db:query(sql)
    if res then
        for key,value in pairs(res) do
            if res[key].content then
                -- ngx.log(ngx.ERR, res[key].id)
                local content = json.decode(res[key].content)
                for k,v in pairs(content) do
                    res[key][k] = v
                end
                res[key].content = nil
            end
        end
    end
    return count,res,orderStats
end

function searchContoller(user, args)
    local count,res, orderStats = search(user, args)
    local json = require "cjson"
    if not res then
        ngx.print(json.encode({
            err = 1,
            msg = '未找到相应的订单'
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = res,
            count = count,
            orderStats = orderStats,
            osTime = os.time()
        }))
        ngx.exit(200)
    end
end

function toCsv(user, args)
    local count,res = search(user, args)
    local file_name = args.file_name or "order.csv"
    local path = "/opt/xyitech/static/"
    local file, err = io.open(path .. file_name, "w+")
    if not file then
        -- ngx.log(ngx.ERR, err)
        ngx.print(json.encode({
            err = 0,
            msg = err
        }))
        ngx.exit(200)
    end
    file:write(getOrderCsvContent(res))
    file:close()
    
    ngx.print(json.encode({
        err = 0,
        msg = res
    }))
    ngx.exit(200)
end

function getOrderCsvContent(tb)
    local csv = "订单编号,日期,飞机编号,起飞,降落,飞行时长, 报纸, 信件, 杂志, 包裹, 其他物品, 运送重量, 备注, 发件人, 收件人, 起点, 终点, 状态 \n"
    
    -- {"letter":0,"t0":1483607988,"id":"2631","aid":"9999","package":0,"serial_no":"170105TR5B0011720","t2":1483608051,"paper":1,"t4":1483613137,"airport":"骞垮満GC锛堝寳渚ч潬杩戦┈璺級","magzine":0,"receiver":"鏉庡崕鏄ユ祴璇�","t5":0,"landing":"","other":0,"model":"TR5B","state":4,"name":"TR5B001","info":"","sender":"鏉庡崕鏄ユ祴璇�","weight":1,"t7":0,"fid":"41","ename":"骞垮満GC锛堝寳渚ч潬杩戦┈璺級","sname":"骞垮満GC锛堟鑺变腑蹇冿級"
    for k,v in pairs(tb) do
        local line = {}
        line[#line + 1] = v.serial_no
        line[#line + 1] = os.date("%y/%m/%d", v.t0)
        line[#line + 1] = v.name
        line[#line + 1] = os.date("%y/%m/%d", v.t2)
        line[#line + 1] = os.date("%y/%m/%d", v.t4)
        line[#line + 1] = string.format("%0.1f", (tonumber(v.t4) - tonumber(v.t2)) / 60)  .. "min"
        line[#line + 1] = v.paper
        line[#line + 1] = v.letter
        line[#line + 1] = v.magzine
        line[#line + 1] = v.package
        line[#line + 1] = v.other
        line[#line + 1] = v.weight
        line[#line + 1] = v.info
        line[#line + 1] = v.sender
        line[#line + 1] = v.receiver
        line[#line + 1] = v.sname
        line[#line + 1] = v.ename
        line[#line + 1] = getStateDetail(v.state)
        csv = csv .. table.concat(line, ",") .. "\n"
    end
    -- ngx.log(ngx.ERR, csv)
    return csv
    -- body
end

function getStateDetail(state)
    local states = {
        [0] = "已创建",
        [1] = "已取消",
        [2] = "已起飞",
        [3] = "订单出错",
        [4] = "已送达",
        [5] = "已确认",
    }
    return states[state] or state
end
function sample()
    local json = require 'cjson'
    local conf = require "conf"
    local db = conf.get_mysql()
    -- local startTime = 1474254000
    -- local secondTime = 1477278000
    local day = 86400
    local records = ""
    local multiple = 1
    local noflydays ={"10/22/16"}
    for startTime=1474254001,1477278000,day do
        if os.date("%w", startTime) ~= "0" and not require("util").contains(noflydays, os.date("%x", startTime)) then
            local res,err = db:query("INSERT INTO `order` SET " .. _oneRecord(startTime, "HG001", "QG001", 1, multiple))
            multiple = 1
        else 
            multiple = multiple + 1
        end
    end
    multiple = 1
    for secondTime=1477278000,os.time(),day do
        if os.date("%w", secondTime) ~= "0" and not require("util").contains(noflydays, os.date("%x", secondTime)) then
            local res,err = db:query("INSERT INTO `order` SET " .. _oneRecord(secondTime, "HG001", "QG001", 1, multiple))
            local res = db:query("INSERT INTO `order` SET " .. _oneRecord(secondTime + 4500, "HG001", "DK001", 2, multiple))
            multiple = 1
        else
            multiple = multiple + 1
        end
    end
    ngx.print(json.encode({
        err = 0,
        msg = "ok"
    }))
    ngx.exit(200)
end

function _oneRecord(startTime, sender, receiver, routeId, multiple)
    local extra = 0;
    if routeId == 2 then
        extra = 120
    end
    local createTime = startTime + math.random() * 600
    local goTime = createTime + math.random() * 900
    local goArriveTime =  goTime + 900 + math.random() * 120  + extra
    local returnTime =  goArriveTime + 600 + math.random() * 500
    local returnArriveTime =  returnTime + 900 + math.random() * 120 + extra
    local content, weight = _sampleContentAndWeight(multiple)
    local vals = {}
    vals[#vals + 1] = "route = " .. routeId
    vals[#vals + 1] = "fid = " .. 1
    vals[#vals + 1] = "aid = " .. 1
    vals[#vals + 1] = "uid = " .. 2
    vals[#vals + 1] = "t0 = " .. math.floor(createTime)
    vals[#vals + 1] = "t2 = " .. math.floor(goTime)
    vals[#vals + 1] = "t4 = " .. math.floor(goArriveTime)
    vals[#vals + 1] = "t5 = " .. math.floor(returnTime)
    vals[#vals + 1] = "t7 = " .. math.floor(returnArriveTime)
    vals[#vals + 1] = "state = 7"
    vals[#vals + 1] = "sender = '" .. sender .. "'"
    vals[#vals + 1] = "receiver = '" .. receiver .. "'"
    vals[#vals + 1] = "serial_no = '" .. _getSerialNo(goTime, "T2B0001") .. "'"
    vals[#vals + 1] = "content = '" .. content .. "'"
    vals[#vals + 1] = "weight = " .. weight
    return table.concat(vals, ",")
end

function _sampleContentAndWeight(multiple)
    local json = require 'cjson'
    local content = {
        ["paper"] = math.floor(20 * multiple),
        ["letter"] = math.floor(1 + math.random() * 5),
        ["magzine"] = math.floor(0 + math.random() * 3),
        ["package"] = math.floor(0 + math.random() * 2),
        ["other"] = math.floor(0 + math.random() * 1.5)
    }
    local weight = content["paper"] * 50 + content["letter"] * 5 + content["magzine"] * 150 + math.floor(content["package"] * (math.random() * 1500))
    return json.encode(content), string.format('%.1f', weight / 1000)

end

function _getSerialNo(goTime, flight_number)
    local date = os.date("%y%m%d", goTime)
    local time = os.date("%H%M%S", goTime)
    return date .. time .. flight_number
end

function calcAverageRouteTime()
    local db = conf.get_mysql()
    local sql = "SELECT id FROM `route` WHERE disabled = 0"
    local res = db:query(sql)
    
    local routeTimes = {}
    if res then
        for k,v in pairs(res) do
            local id  = v.id
            
            sql = "SELECT t2, t5, route FROM `order` WHERE t5 != 0 AND route = " .. id .. " ORDER BY t4 LIMIT 5"
            res = db:query(sql)
            ngx.log(ngx.ERR, json.encode(res))
            if res and #res > 0 then
                routeTimes[id] = util.reduce(res, function (acc, cur) return acc + (tonumber(cur.t5) - tonumber(cur.t2)) end, 0) / #res
                sql = "UPDATE route set duration = " .. routeTimes[id] .. " WHERE id = " .. id
                res = db:query(sql)
            end

        end
    end

    -- ngx.log(ngx.ERR, json.encode(routeTimes))
    ngx.print(json.encode({
        err = 0,
        msg = routeTimes
    }))
    ngx.exit(200)
end

local function packRawData(data)
    local json = require 'cjson'
    local arr = {}
    local p = 0
    if not data or data == ngx.null then
        data = {}
    end
    local len = #data
    while p < len do
        local packLen = xbit.readBuff(_uint32_t, data, p)
        -- ngx.log(ngx.ERR, packLen)
        p = p + 4
        if packLen <= len then
            arr[#arr + 1] = string.sub(data, p + 1, packLen + p)
        else
            ngx.log(ngx.ERR, "package length error on " .. p)
        end
        p = p + packLen
    end
    -- ngx.log(ngx.ERR, json.encode(arr))
    return arr
end

local function parse(oneMessage)
    -- local m = xbit.readBuff(_uint8_t, oneMessage, 0)
    -- ngx.log(ngx.ERR, m)
    -- local m1 = xbit.readBuff(_uint8_t, oneMessage, 1)
    -- ngx.log(ngx.ERR, m1)
    local res = nil
    local server_time_std_s = 0
    res = protocal.toTable(oneMessage)
    -- ngx.log(ngx.ERR, json.encode(res))

    -- ngx.log(ngx.ERR, xbit.readBuff(_uint8_t, oneMessage, 0))

    server_time_std_s = xbit.readBuff(_uint32_t, oneMessage, (string.len(oneMessage) - 4))
    table.insert(res, server_time_std_s)
    return res
end

local function toAnalyzeLine(v)
    local line = {}
    -- ngx.log(ngx.ERR, json.encode)
    if v["1"] then 
        --time_std_s

        line.time_std_s =  v["1"][3]
        -- ngx.log(ngx.ERR, json.encode(line))
        --server_time_std_s
        line.server_time_std_s= v["1"][8]
        --fid
        line.fid = v["1"][2]
        --mode
        line.mode = v["1"][5]
    end

    if v["2"] then
        --voltage
        line.voltage = v["2"][4]
        --current_battery
        line.current_battery = v["2"][14]
        --battery_remaining
        line.battery_remaining = v["2"][15]

        line.battery_life_factor = v["2"][16]

        line.uav_load_factor = v["2"][17]
        --time_can_fly
        line.time_can_fly = v["2"][18]

        line.time_needed = v["2"][19]
    end

    if v["3"] then
        --x
        line.x = tonumber(string.format("%0.2f", v["3"][4]))
        --y
        line.y = tonumber(string.format("%0.2f", v["3"][5]))
        --z
        line.z = tonumber(string.format("%0.2f", v["3"][6]))
        --vx
        line.vx = tonumber(string.format("%0.2f", v["3"][7]))
        --vy
        line.vy = tonumber(string.format("%0.2f", v["3"][8]))
        --vz
        line.vz = tonumber(string.format("%0.2f", v["3"][9]))
        --ultra_alt
        line.ultra_alt = tonumber(string.format("%0.2f", v["3"][10]))
        --dis_m
        line.dis_m = tonumber(string.format("%0.2f", v["3"][11]))
    end

    if v["4"] then
        --relative_alt
        line.relative_alt = tonumber(string.format("%0.1f", v["4"][4]))
        --pitch_deg
        line.pitch_deg = v["4"][5]
        --roll_deg
        line.roll_deg = v["4"][6]
        --hdg
        line.hdg = v["4"][7]
    end

    if v["5"] then
        --gps_lat
        line.gps_lat =  tonumber(string.format("%0.5f", v["5"][5]))
        --gps_lng
        line.gps_lng =  tonumber(string.format("%0.5f", v["5"][6]))
        --vel_gps
        line.vel_gps = v["5"][10]

        --alt_rel_pres
        line.alt_rel_pres = tonumber(string.format("%0.2f", v["5"][7]))

        line.eph = tonumber(string.format("%0.2f", v["5"][8]))

        line.epv = tonumber(string.format("%0.2f", v["5"][9]))

        line.cog = v["5"][11]

        line.satellites_visible = v["5"][12]
    end

    if v["6"] then
        line.vision_reg_num = v["6"][4]

        line.vision_x_ned = v["6"][5]

        line.vision_y_ned = v["6"][6]

        line.vision_z_ned = v["6"][7]
    end

    if v["8"] then
        --throttle
        line.throttle = tonumber(string.format("%0.2f", v["8"][4]))

        line.actuator_pitch = tonumber(string.format("%0.2f", v["8"][5]))

        line.actuator_roll = tonumber(string.format("%0.2f", v["8"][6]))

        line.actuator_yaw = tonumber(string.format("%0.2f", v["8"][7]))

        line.throttle_threshold_by_weight = tonumber(string.format("%0.2f", v["8"][8]))
    end
    
    if v["9"] then
        line.alarm_ID = v["9"][5]

        line.alarm_level = v["9"][6]

        line.param1 = v["9"][7]

        line.param2 = v["9"][8]

        line.param3 = v["9"][9]

        line.param4 = v["9"][10]

        line.param5 = v["9"][11]
    end

    if v["10"] then
        line.alarm_ID_release = v["10"][5]
    end

    if v["101"] then
        line.msg_101_uid = v["101"][3]
        line.command_101 = v["101"][5]
        for i = 0, 7 do
            line.command_101_params = line.command_101_params .. v["101"][i + 7]
        end
    end

    if v["102"] then
        line.msg_102_command = v["102"][3]
        line.msg_102_result = v["102"][4]
    end

    if v["105"] then
        line.msg_105_uid = v["105"][3]
        line.msg_105_count = v["105"][5]
        line.msg_105_frame = v["105"][6]

    end

    if v["106"] then
        line.msg_106_type = v["106"][4]
    end
    return line

end

local function getMode(history, mode, ifEnd)
    local flag = false
    for i = 1,#history do
        -- ngx.log(ngx.ERR, json.encode(history[i]))
        -- ngx.log(ngx.ERR, mode)
        if history[i].mode == mode then
            flag = true
            return history[i],i
        elseif flag and history[i].mode ~= mode then
            return history[i - 1], i - 1 
        end
    end
    return {},1
end

function toAnalyzeData(orderDetail, data, startTime, red, withLog)
    local json = require 'cjson'
    local arr = packRawData(data)
    local prefix = "time_std_s,server_time_std_s,fid,mode,voltage,current_battery,battery_remaining,battery_life_factor,uav_load_factor,time_can_fly, time_needed, x, y, z, vx, vy, vz, ultra_alt, dis_m, relative_alt,pitch_deg,roll_deg,hdg,gps_lat,gps_lng, alt_rel_pres, eph, epv,vel_gps,cog, satellites_visible, vision_reg_num, vision_x_ned, vision_y_ned, vision_z_ned, throttle, actuator_pitch, actuator_roll, actuator_yaw, throttle_threshold_by_weight,alarm_ID, alarm_level, param1, param2, param3, param4, param5, alarm_ID_release"
    -- prefix = table.concat(prefix, ",")
    local result = {}
    local offset = {}
    local routeDetail = json.decode(orderDetail.routeDetail)
    local now = os.time()
    local fid = 0
    for index, oneMessage in pairs(arr) do
        -- ngx.log(ngx.ERR, oneMessage)
        if #oneMessage >= 0 then
            local pk = parse(oneMessage)
            -- ngx.log(ngx.ERR, json.encode(pk))
            if pk and #pk > 1 then
                local msgId = pk[1]
                fid = pk[2]
                local time_std_s = pk[3]
                if not result[pk[3]] then
                    result[pk[3]] = {}
                end
                result[pk[3]][msgId..""] = pk
            end
        end
    end

    local res, reportData = {} , {["count"] = 0, ["timeCanFly"] = 0, ["volt"] = 0, ["throttle"] = 0, ["lastMode"] = 0, ["history"] = {}, ["maxV"] = 0, ["maxAlt"] = 0, ["maxPitchDeg"] = 0 , ["maxRollDeg"] = 0 , ["lastMessage"] = {}}
    -- ngx.log(ngx.ERR, json.encode(result))
    local log = {}
    local key_table = {}
    for key,_ in pairs(result) do  
         -- ngx.log(ngx.ERR, key)
         -- ngx.log(ngx.ERR, type(key))
        table.insert(key_table, tonumber(key))
    end
    table.sort(key_table)
    for _,key in pairs(key_table) do
        local v = result[key]
        if v then
            local line = toAnalyzeLine(v)
            -- ngx.log(ngx.ERR, json.encode(line))

            if line then

                if not reportData.count then
                    reportData.count = 0
                end
                reportData.count = reportData.count + 1

                if reportData.timeCanFly == 0 and line.time_can_fly then
                    reportData.timeCanFly = line.time_can_fly
                end
                if reportData.throttle == 0 and line.throttle then
                    reportData.throttle = line.throttle
                end
                if reportData.volt == 0 and line.voltage then
                    reportData.volt = line.voltage
                end
                if line.mode and reportData.lastMode ~= line.mode then
                    reportData.lastMode = line.mode
                    if not reportData.history then
                        reportData.history = {}
                    end
                    table.insert(reportData.history, line)
                end

                if reportData.maxV == 0 and line.vel_gps then
                    reportData.maxV = line.vel_gps
                end
                if line.vel_gps and reportData.maxV < line.vel_gps then
                    reportData.maxV = line.vel_gps
                end

                if reportData.maxPitchDeg == 0 and line.pitch_deg then
                    reportData.maxPitchDeg = line.pitch_deg
                end
                if line.pitch_deg and math.abs(reportData.maxPitchDeg) < math.abs(line.pitch_deg) then
                    reportData.maxPitchDeg = math.abs(line.pitch_deg)
                end

                if reportData.maxRollDeg == 0 and line.roll_deg then
                    reportData.maxRollDeg = line.roll_deg
                end
                if line.roll_deg and math.abs(reportData.maxRollDeg) < math.abs(line.roll_deg) then
                    reportData.maxRollDeg = math.abs(line.roll_deg)
                end

                if reportData.maxAlt == 0 and line.relative_alt then
                    reportData.maxAlt = line.relative_alt
                end
                if line.relative_alt and reportData.maxAlt < line.relative_alt then
                    reportData.maxAlt = line.relative_alt
                end

                reportData.lastMessage = line
                local prefixArr = util.split(prefix, ",")
                local logLine = {}
                for i = 1, #prefixArr do
                    local l = line[util.trim(prefixArr[i])] or "-"
                    if prefixArr[i] == "server_time_std_s" or prefixArr[i] == "time_std_s" then
                        if prefixArr[i] and prefixArr[i] ~= "" then
                            l = os.date("%H:%M:%S", tonumber(l))
                        end
                    end
                    table.insert(logLine, l)
                end
                log[#log + 1] = table.concat(logLine, ",") .. "\n"
            end
        end
    end
    
    local duration = 0
    if orderDetail.t5 ~= 0 then
        duration = orderDetail.t5 - orderDetail.t2
    elseif reportData.lastMessage and reportData.lastMessage.server_time_std_s then
        duration = reportData.lastMessage.server_time_std_s - orderDetail.t2
    end
    local lastRoutePoint = routeDetail[#routeDetail]
    offset.lat = lastRoutePoint.lat
    offset.lng = lastRoutePoint.lng
    local mode3 = getMode(reportData.history, 3)

    res[#res + 1] = orderDetail.serial_no .. " 飞行报告\n"
    res[#res + 1] = "参数名称, 数值, 单位\n"
    res[#res + 1] = "起点, " .. orderDetail.sname ..",-\n"
    res[#res + 1] = "终点, " .. orderDetail.ename ..",-\n"
    res[#res + 1] = "航线ID, " .. orderDetail.routeId .. ",-\n"
    res[#res + 1] = "航线名称, " .. orderDetail.routeName .. ",-\n"
    res[#res + 1] = "预计飞行距离, " .. orderDetail.distance .. ",m\n"
    res[#res + 1] = "预计飞行时间, ".. orderDetail.duration .. ",s\n"
    res[#res + 1] = "飞机可飞时间, " .. reportData.timeCanFly .. ",s\n"
    res[#res + 1] = "航线高度差, ".. orderDetail.height_diff .. ",m\n"
    res[#res + 1] = "飞机ID, " .. orderDetail.fid .. ",-\n"
    res[#res + 1] = "飞机版本, " .. orderDetail.plane_version_number .. ",-\n"
    res[#res + 1] = "飞机hash, " .. orderDetail.plane_hashcode .. ",-\n"
    res[#res + 1] = "电池ID, " .. orderDetail.bid .. ",-\n"
    local w = string.format("%0.1f", orderDetail.weight)
    res[#res + 1] = "货物重量, " .. w .. ",kg\n"
    local aw = mode3.uav_load_factor and string.format("%0.1f", mode3.uav_load_factor) or "-"
    res[#res + 1] = "推算重量, " .. aw .. ", kg\n"
    -- res[#res + 1] = "uav_load_factor, " .. mode3.uav_load_factor .. ", -\n"
    local th = string.format("%0.3f", reportData.throttle)
    res[#res + 1] = "起飞参考油门, " .. th .. ",-\n"
    local volt = string.format("%0.2f",reportData.volt/1000)
    res[#res + 1] = "电池电压-起飞后, " .. volt .. ",V\n"

    -- local mode3 = getMode(reportData.history, 3)
    res[#res + 1] = "电池电量-上线, " .. (mode3.battery_remaining or "_").. ",%\n"

    local mode4 = getMode(reportData.history, 4)
    res[#res + 1] = "电池电量-爬升, " .. (mode4.battery_remaining or "-").. ",%\n"

    local mode6 = getMode(reportData.history, 6)
    res[#res + 1] = "电池电量-降落, " .. (mode6.battery_remaining or "-") .. ",%\n"

    local mode11,index = getMode(reportData.history, 11)
    -- ngx.log(ngx.ERR, index)
    res[#res + 1] = "电池电量-着陆, " .. (mode11.battery_remaining or "_").. ",%\n"
    res[#res + 1] = "预计落地电量, " ..  orderDetail.battery_after_flight * 100 .. ",%\n"
    if not mode4.gps_lat then
        mode4.gps_lat = 0
    end

    if not mode4.gps_lng then
        mode4.gps_lng = 0
    end
    res[#res + 1] = "爬升开始时gps_lat, " .. (string.format("%0.5f", mode4.gps_lat) or "-").. ",-\n"
    res[#res + 1] = "爬升开始时gps_lng, " .. (string.format("%0.5f", mode4.gps_lng) or "-").. ",-\n"

    local mode4End, index = getMode(reportData.history, 4, true)
    if not mode4End.gps_lat then
        mode4End.gps_lat = 0
    end
    if not mode4End.gps_lng then
        mode4End.gps_lng = 0
    end
    res[#res + 1] = "爬升结束时gps_lat, " .. (string.format("%0.5f", mode4End.gps_lat) or "-").. ",-\n"
    res[#res + 1] = "爬升结束时gps_lng, " .. (string.format("%0.5f", mode4End.gps_lng) or "-").. ",-\n"

    res[#res + 1] = "起飞时刻,"..os.date("%H:%M:%S", orderDetail.t2)..",hh:mm:ss\n"
    local landing = orderDetail.t5 == 0 and "-" or os.date("%H:%M:%S", orderDetail.t5)
    res[#res + 1] = "着陆时刻,"..landing..",hh:mm:ss\n"
    if not mode3.dis_m then
        mode3.dis_m = 0
    end
    if not reportData.lastMessage.dis_m then
        reportData.lastMessage.dis_m = 0
    end
    local dis = reportData.lastMessage.dis_m - mode3.dis_m
    res[#res + 1] = "实际飞行距离, " .. dis .. ",m\n"
    res[#res + 1] = "实际飞行时间,".. util.secondsToMS(duration)..",mm:ss\n"
    res[#res + 1] = "离线时间,".. util.secondsToMS(duration - reportData.count)..",mm:ss\n"
    res[#res + 1] = "最大飞行速度," .. reportData.maxV .. ",m/s\n"
    res[#res + 1] = "最大飞行高度," .. reportData.maxAlt .. ",m\n"
    res[#res + 1] = "最大俯仰角," .. reportData.maxPitchDeg .. ",-\n"
    res[#res + 1] = "最大滚转角," .. reportData.maxRollDeg .. ",-\n"
    local mode6 = getMode(reportData.history, 6)
    local ra = mode6.relative_alt and string.format("%0.1f", mode6.relative_alt) or "-"
    res[#res + 1] = "航线终点飞机高度," .. ra .. ",m\n"
    local arp = mode6.alt_rel_pres and string.format("%0.1f", mode6.alt_rel_pres) or "-"
    res[#res + 1] = "航线终点飞机气压高度," .. (getMode(reportData.history, 6).alt_rel_pres or  "_") .. ",m\n"
    local x = mode6.x and string.format("%0.2f", mode6.x) or "-"
    res[#res + 1] = "航线终点飞机x坐标," .. x .. ",m\n"
    local y = mode6.y and string.format("%0.2f", mode6.y) or "-"
    res[#res + 1] = "航线终点飞机y坐标," .. y .. ",m\n"
    if not mode6.gps_lat then
        mode6.gps_lat = 0
    end
    if not mode6.gps_lng then
        mode6.gps_lng = 0
    end
    if not mode11.gps_lat then
        mode11.gps_lat = 0
    end
    if not mode11.gps_lng then
        mode11.gps_lng = 0
    end
    res[#res + 1] = "航线终点飞机gps_lat, " .. (string.format("%0.5f", mode6.gps_lat) or "-").. ",-\n"
    res[#res + 1] = "航线终点飞机gps_lng, " .. (string.format("%0.5f", mode6.gps_lng) or "-").. ",-\n"


    local ra = mode11.relative_alt and string.format("%0.1f", mode11.relative_alt) or "-"
    res[#res + 1] = "飞机着陆高度," .. ra .. ",m\n"
    local arp = mode11.alt_rel_pres and string.format("%0.1f", mode11.alt_rel_pres) or "-"
    res[#res + 1] = "飞机着陆气压高度," .. arp .. ",m\n"
    local x = mode11.x and string.format("%0.2f", mode11.x) or "-"
    res[#res + 1] = "飞机着陆x坐标," .. x .. ",m\n"
    local y = mode11.y and string.format("%0.2f", mode11.y) or "-"
    res[#res + 1] = "飞机着陆y坐标," .. y .. ",m\n\n"
    res[#res + 1] = "飞机着陆gps_lat, " .. (string.format("%0.5f", mode11.gps_lat) or "-").. ",-\n"
    res[#res + 1] = "飞机着陆gps_lng, " .. (string.format("%0.5f", mode11.gps_lng) or "-").. ",-\n"
    

    offset.deltaLat = string.format("%0.5f", (mode11.gps_lat - mode6.gps_lat))
    offset.deltaLng = string.format("%0.5f", (mode11.gps_lng - mode6.gps_lng))
    offset.lat = string.format("%0.5f", offset.lat + offset.deltaLat)
    offset.lng = string.format("%0.5f",offset.lng + offset.deltaLng)
    if not mode6.relative_alt then
        mode6.relative_alt = 0
    end

    if not mode6.alt_rel_pres then
        mode6.alt_rel_pres = 0
    end
    if not mode11.alt_rel_pres then
        mode11.alt_rel_pres = 0
    end
    offset.deltaLat = offset.deltaLat * 1e5
    offset.deltaLng = offset.deltaLng * 1e5
    offset.alt = string.format("%0.1f", mode6.relative_alt - (mode6.alt_rel_pres - mode11.alt_rel_pres - 60))
    offset.height_diff = string.format("%0.1f", mode11.alt_rel_pres) + orderDetail.salt
    res[#res + 1] = "时间, 事件\n"
    for i=1,#reportData.history do
        local h = reportData.history[i]

        for j=1, #orderDetail.orderReportDetail do
            ngx.log(ngx.ERR, orderDetail.orderReportDetail[j].create_time)
            ngx.log(ngx.ERR, orderDetail.orderReportDetail[j].order_id)
            if orderDetail.orderReportDetail[j].create_time < h.server_time_std_s then
                res[#res + 1] = os.date("%H:%M:%S", orderDetail.orderReportDetail[j].create_time) .. "," .. "问题" .. "\n"
            end
        end

        if h.server_time_std_s and h.mode and util.modeToDesc(h.mode) then
            res[#res + 1] = os.date("%H:%M:%S", h.server_time_std_s) .. "," .. util.modeToDesc(h.mode) .. "\n"
        end
    end

    if withLog then
        res[#res + 1] = "\n".. prefix.. "\n"
        -- table.concat(res, "\n")
        for i = 1, #log do
            table.insert(res, log[i])
        end
    end
    
    return res,offset,result
end

function analyze(user, args)
    local db = conf.get_mysql()
    local route = require 'route'
    local orderReport = require 'order_report'
    local fid, serial_no, temp_takeoff, temp_takeoff_pa, temp_landing, pre_landing_pa, num_battery, weight_g = args.fid, args.serial_no, args.temp_takeoff, args.temp_takeoff_pa, args.temp_landing, args.pre_landing_pa, args.num_battery, args.weight_g
    local startTime, duration,light_takeoff, light_landing, order_id = tonumber(args.t2), args.duration, args.light_takeoff, args.light_landing, args.order_id
    duration = duration or 86400
    temp_takeoff = temp_takeoff or 0
    temp_takeoff_pa = temp_takeoff_pa or 0
    temp_landing = temp_landing or 0
    pre_landing_pa = pre_landing_pa or 0
    num_battery = num_battery or 0
    weight_g = weight_g or 0
    light_takeoff = light_takeoff or 0
    light_landing = light_landing or 0
    local prefix = {serial_no, temp_takeoff, temp_takeoff_pa, light_takeoff, temp_landing, light_landing, pre_landing_pa, num_battery, weight_g}
    local path = fid
    local red = conf.get_redis()

    if order_id then
        path = "order_id_" .. order_id
    end

    local fidBuffer, err = red:get(path)

    if err or not fidBuffer then
        ngx.print(json.encode({
            err = 1,
            msg = "无法取得相应数据 fid: " .. fid
        }))
        ngx.exit(200)
    end
    local count,orderDetail = search(user, {["id"] = order_id})
    local orderReportDetail = orderReport.search(user, {["order_id"] = order_id}) or {}
    local routeDetail = route.search(user, {["id"] = orderDetail[1].routeId})

    ngx.log(ngx.ERR, json.encode(routeDetail))

    orderDetail[1].routeDetail = routeDetail[1].detail
    orderDetail[1].salt = routeDetail[1].salt
    orderDetail[1].ealt = routeDetail[1].ealt
    orderDetail[1].orderReportDetail = orderReportDetail or {}
    local res = toAnalyzeData(orderDetail[1], fidBuffer, startTime, red, true)

    ngx.header.content_type = "application/octet-stream"
    ngx.header.content_disposition = "attachment; filename=" .. serial_no .. '.csv'

    ngx.print(res)
    ngx.log(ngx.ERR, "analyze finish")
    ngx.exit(200)
end


function analyzeHtml(user, args)
    local db = conf.get_mysql()
    local route = require 'route'
    local orderReport = require 'order_report'
    local fid, serial_no, temp_takeoff, temp_takeoff_pa, temp_landing, pre_landing_pa, num_battery, weight_g = args.fid, args.serial_no, args.temp_takeoff, args.temp_takeoff_pa, args.temp_landing, args.pre_landing_pa, args.num_battery, args.weight_g
    local startTime, duration,light_takeoff, light_landing, order_id = tonumber(args.t2), args.duration, args.light_takeoff, args.light_landing, args.order_id
    duration = duration or 86400
    temp_takeoff = temp_takeoff or 0
    temp_takeoff_pa = temp_takeoff_pa or 0
    temp_landing = temp_landing or 0
    pre_landing_pa = pre_landing_pa or 0
    num_battery = num_battery or 0
    weight_g = weight_g or 0
    light_takeoff = light_takeoff or 0
    light_landing = light_landing or 0
    local prefix = {serial_no, temp_takeoff, temp_takeoff_pa, light_takeoff, temp_landing, light_landing, pre_landing_pa, num_battery, weight_g}
    local path = fid
    local red = conf.get_redis()
    if order_id then
        path = "order_id_" .. order_id
    end

    local fidBuffer, err = red:get(path)
    if err or not fidBuffer then
        ngx.print(json.encode({
            err = 1,
            msg = "无法取得相应数据 fid: " .. fid
        }))
        ngx.exit(200)
    end
    local count,orderDetail = search(user, {["id"] = order_id})
    local orderReportDetail = orderReport.search(user, {["order_id"] = order_id}) or {}
    local routeDetail = route.search(user, {["id"] = orderDetail[1].routeId})
    ngx.log(ngx.ERR, json.encode(routeDetail))

    orderDetail[1].routeDetail = routeDetail[1].detail
    orderDetail[1].salt = routeDetail[1].salt
    orderDetail[1].ealt = routeDetail[1].ealt
    orderDetail[1].orderReportDetail = orderReportDetail or {}
    local res,offset,result = toAnalyzeData(orderDetail[1], fidBuffer, startTime, red, false)

    ngx.log(ngx.ERR, "analyze finish")
    return res, offset, result
end

function analyzeHtmlController(user, args)
    local res, offset, result = analyzeHtml(user, args)
    ngx.print(json.encode({
        err = 0,
        msg = res,
        offset = offset
    }))
    ngx.exit(200)
end
function calcOneDayOrderStats(user, args)
    local db = conf.get_mysql()
    args.start_time = args.start_time or os.time()
    args.end_time = args.end_time or os.time()

    local start_time = args.start_time
    local end_time = args.end_time
    local sql = "SELECT `order`.id, `order`.route, `order`.t0,`order`.t4, `order`.t5, `order`.schedule_id, `order`.flight_number, `plane`.model, `route`.distance FROM `order` left join `plane` on `order`.fid = `plane`.id left join `route` on `route`.id = `order`.route WHERE 1 = 1"
    sql =  sql .. " AND ((`order`.t4 >=" .. tonumber(start_time) .. " AND `order`.t4 <= " .. tonumber(end_time) .. ")"
    sql =  sql .. " OR (`order`.t5 >= " .. tonumber(start_time) .. " AND `order`.t5 <= " .. tonumber(end_time).. "))"
    sql =  sql .. " AND `plane`.model != 'SIM' "

    sql = sql .. " AND `order`.aid in (" ..  table.concat(user.aids, ",") .. ")"

    sql = sql .. " AND `order`.org_id in (" ..  table.concat(user.orgIds, ",") .. ")"

    ngx.log(ngx.ERR, sql)
    local orders = db:query(sql)
    return orders
end

function sortOrderStats(orders, start_date, end_date)
    local res = {
        ["count"] = {
            ["year"] = {},
            ["month"] = {},
            ["day"] = {},
            ["hour"] = {}
        },
        ["distance"] = {
            ["year"] = {},
            ["month"] = {},
            ["day"] = {},
            ["hour"] = {}
        }
    }
    -- local year, month, day = {}, {}, {}
    -- local dateTable = os.date("*t", os.time())
    local now = os.time()
    local timeTable = nil
    local duration = 0


    if not start_date and not end_date then
        timeTable = os.date("*t", now)
        ngx.log(ngx.ERR, json.encode(timeTable))
    else
        ngx.log(ngx.ERR, util.timeStringToStamp(start_date .. " 24:00:00"))
        duration = (util.timeStringToStamp(end_date .. " 24:00:00") - util.timeStringToStamp(start_date .. " 00:00:00")) / 86400
        ngx.log(ngx.ERR, duration)
    end

    local currentTime = util.zero_clock_of_year(now)
    for i = 1,#orders do
        -- ngx.log(ngx.ERR, json.encode(orders[i]))
        local currentTimeTable = os.date("*t", orders[i].t0)
        if true or orders[i].t4 > 0 or orders[i].t5 > 0 then
        -- ngx.log(ngx.ERR, json.encode(currentTimeTable))
            if (timeTable) or (not timeTable and duration > 365) then
                if not res.distance.year[currentTimeTable.year..""] then
                    res.distance.year[currentTimeTable.year..""] = orders[i].distance
                else
                    res.distance.year[currentTimeTable.year..""] = res.distance.year[currentTimeTable.year..""] + orders[i].distance
                end

                if not res.count.year[currentTimeTable.year..""] then
                    res.count.year[currentTimeTable.year..""] = 1
                else
                    res.count.year[currentTimeTable.year..""] = res.count.year[currentTimeTable.year..""] + 1
                end
            end
                    -- ngx.log(ngx.ERR, json.encode(year))
            if (timeTable and util.withinLast12Monthes(currentTimeTable)) or (not timeTable and duration > 31 and duration <= 365) then
                local key = currentTimeTable.year .. "-" .. currentTimeTable.month
                if not res.distance.month[key] then
                    res.distance.month[key] = orders[i].distance
                else
                    res.distance.month[key] = res.distance.month[key] + orders[i].distance
                end

                if not res.count.month[key] then
                    res.count.month[key] = 1
                else
                    res.count.month[key] = res.count.month[key] + 1
                end
            end

            if  (timeTable and util.withinLast30Days(currentTimeTable)) or (not timeTable and duration > 1 and duration <= 31) then
                local key  = currentTimeTable.year .. "-" .. currentTimeTable.month .. "-" .. currentTimeTable.day
                -- ngx.log(ngx.ERR, key)
                if not res.distance.day[key] then
                    res.distance.day[key] = orders[i].distance
                else
                    res.distance.day[key] = res.distance.day[key] + orders[i].distance
                end

                if not res.count.day[key] then
                    res.count.day[key] = 1
                else
                    res.count.day[key] = res.count.day[key] + 1
                end
            end

            if (timeTable and timeTable.year == currentTimeTable.year and timeTable.month == currentTimeTable.month and timeTable.day == currentTimeTable.day) or (not timeTable and duration > 0 and duration <= 1) then
                local key  = currentTimeTable.year .. "-" .. currentTimeTable.month .. "-" .. currentTimeTable.day .. "-" .. currentTimeTable.hour
                if not res.distance.hour[key] then
                    res.distance.hour[key] = orders[i].distance
                else
                    res.distance.hour[key] = res.distance.hour[key] + orders[i].distance
                end

                if not res.count.hour[key] then
                    res.count.hour[key] = 1
                else
                    res.count.hour[key] = res.count.hour[key] + 1
                end
            end
        end
    end
    return res
end

function calcOrderStats(user, args)
    local yearDate = util.zero_clock_of_year(os.time())
    args.notSim = true
    args.yearDate = yearDate
    local res, count, orderStats = search(user, args)
    ngx.print(json.encode({
        err = 0,
        msg = orderStats
    }))
    ngx.exit(200)
end


function applyTakeoff(user, args)
    local message = require "message"
    -- local order = require "order"
    local _user = require "user"
    local res, err
    if user.role_id == 4 then
        res, err = update(user, {["state"] = 6, ["id"] = args.id, ["autoApprove"] = true})
    else    
        local admin_phone = 0
        res, err = update(user, {["state"] = 8, ["id"] = args.id, ["resetTimes"] = true})
        ngx.log(ngx.ERR, err)
        ngx.log(ngx.ERR, json.encode(args))
        res = _user.search(user, {["id"] = _jieyan_takeoff_admin})
        if res and res[1] then
            admin_phone = res[1].phone
        end
        ngx.log(ngx.ERR, admin_phone)
        local res = message.createTakeoffApproveMessage(user, {["phone"]= admin_phone,["sname"]= args.sname, ["ename"]= args.ename, ["to_uid"] = _jieyan_takeoff_admin, ["id"] = args.id, ["serial_no"]= args.serial_no, ["flight_number"]= args.flight_number})
        if args.to_uid and args.to_uid ~= 0 then
            ngx.log(ngx.ERR, "to_uid")
            res = message.createTakeoffApproveMessage(user, {["phone"]= args.phone, ["sname"]= args.sname, ["ename"]= args.ename, ["to_uid"] = args.to_uid, ["id"] = args.id, ["serial_no"]= args.serial_no, ["flight_number"]= args.flight_number})
        end
        if args.to_uid2 and args.to_uid ~= args.to_uid2 and args.to_uid2 ~= 0 then
            ngx.log(ngx.ERR, "to_uid2")
            res = message.createTakeoffApproveMessage(user, {["phone"]= args.phone2,["sname"]= args.sname, ["ename"]= args.ename,  ["to_uid"] = args.to_uid2, ["id"] = args.id, ["serial_no"]= args.serial_no, ["flight_number"]= args.flight_number})
        end
        local body = user.name .. "于" .. os.date("%H:%M", os.time()) .. "发送了" .. args.sname .. "-" .. args.ename .. "的寄件申请"
        message.create(user, {["to_uid"] = 0, ["type"] = "normal", ["header"] = "系统消息", ["body"] = body})
    end
    return res
end

function applyTakeoffController(user, args)
    if not args.id then
        ngx.print(json.encode({
            err = 1,
            msg = "参数不对"
        }))
        ngx.exit(200)
    end
    local db = conf.get_mysql()
    local res = db:query("SELECT route, serial_no, flight_number from `order` WHERE id = " .. args.id)
    if not res then
        ngx.print(json.encode({
            err = 3,
            msg = "订单信息有误"
        }))
        ngx.exit(200)
    end
    args.serial_no = res[1].serial_no
    args.flight_number = res[1].flight_number
    local route = res[1].route
    local res = db:query("SELECT `spoint`.id, `spoint`.uid, `spoint`.uid2, `spoint`.contact_name, `spoint`.contact_name2, `spoint`.phone, `spoint`.phone2,`spoint`.name from `route` left join `spoint` on `route`.eid = `spoint`.id where `route`.id = " .. route)
    if not res or not res[1] then
        ngx.print(json.encode({
            err = 4,
            msg = "航路或站点信息有误"
        }))
        ngx.exit(200)
    end
    args.ename = res[1].name
    args.contact_name = res[1].contact_name
    args.contact_name2 = res[1].contact_name2
    args.to_uid = res[1].uid
    args.to_uid2 = res[1].uid2
    args.phone = res[1].phone
    args.phone2 = res[1].phone2
    local res = db:query("SELECT `spoint`.id, `spoint`.name from `route` left join `spoint` on `route`.sid = `spoint`.id where `route`.id = " .. route)
    if not res or not res[1] then
        ngx.print(json.encode({
            err = 4,
            msg = "航路或站点信息有误"
        }))
        ngx.exit(200)
    end
    args.sname = res[1].name
    local message = require "message"

    local count = #(message.getMessageWithOrderId({["id"] = args.id}))
    if count > 2 then
        ngx.print(json.encode({
            err = 3,
            msg = "该订单已存在生效申请"
        }))
        ngx.exit(200)
    end

    
    local res = applyTakeoff(user, args)
    if not res then
        ngx.print(json.encode({
            err = 2,
            msg = "发生错误"
        }))
        ngx.exit(200)
    else
        ngx.print(json.encode({
            err = 0,
            msg = "成功"
        }))
        ngx.exit(200)
    end
end


function getContactsByOrderId(user, args)
    local db = conf.get_mysql()
    local details = {}
    local user = require 'user'
    local res = db:query("SELECT to_uid, to_uid2 from `order` WHERE id = " .. args.id)
    if not res then
        ngx.print(json.encode({
            err = 2,
            msg = "订单信息有误"
        }))
        ngx.exit(200)
    end
    local jieyan_admin,spoint_admin_1,spoint_admin_2 = nil, nil, nil
    jieyan_admin = db:query("SELECT id, name, phone FROM `user` where id = " .. _jieyan_takeoff_admin)
    details.jieyan_admin = jieyan_admin[1]
    if res[1].to_uid ~= 0 then
        spoint_admin_1 = db:query("SELECT id, name, phone FROM `user` where id = " .. res[1].to_uid)
        details.spoint_admin_1 = spoint_admin_1[1]
    end
    if res[1].to_uid2 ~= 0 then
        spoint_admin_2 = db:query("SELECT id, name, phone FROM `user` where id = " .. res[1].to_uid2)
        details.spoint_admin_2 = spoint_admin_2[1]
    end
    return details
end

function getContactsByOrderIdController(user, args)
    if not args.id then
        ngx.print(json.encode({
            err = 1,
            msg = "参数不对"
        }))
        ngx.exit(200)
    end
    local res = getContactsByOrderId(user, args)
    if not res then
         ngx.print(json.encode({
            err = 2,
            msg = "发生错误"
        }))
        ngx.exit(200)
    end
    ngx.print(json.encode({
        err = 0,
        msg = res
    }))
    ngx.exit(200)
end

function default(args)
    local user = conf.parse_token(args, "order")
    if args.action == 'create' then
        createController(user, args)
    elseif args.action == 'list' then
        listController(user, args)
    elseif args.action == 'update' then
        updateController(user, args)
    elseif args.action == 'detail' then
        detailController(user, args)
    elseif args.action == 'search' then
        searchContoller(user, args)
    elseif args.action == 'applyTakeoff' then
        applyTakeoffController(user, args)
    elseif args.action == '_autoTakeOff' then
        _autoTakeOff(user, args)
    elseif args.action == 'sample' then
        sample()
    elseif args.action == 'toCsv' then
        toCsv(user, args)
    elseif args.action == 'calcAverageRouteTime' then
        calcAverageRouteTime()
    elseif args.action == 'analyze' then
        analyze(user, args)
    elseif args.action == 'analyzeHtml' then
        analyzeHtmlController(user, args)
    elseif args.action == 'takeOffPreCheck' then
        takeOffPreCheckController(user, args)
    elseif args.action == 'calcOrderStats' then
        calcOrderStats(user, args)
    elseif args.action == 'getContactsByOrderId' then
        getContactsByOrderIdController(user, args)
    end
end

local class_mt = {
    __newindex = function (table, key, val)
        error('attempt to write to undeclared variable "' .. key .. '"')
    end
}
setmetatable(_M, class_mt)